package com.deng.framework.aop.framework.autoproxy;

import com.deng.framework.aop.*;
import com.deng.framework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import com.deng.framework.aop.framework.ProxyFactory;
import com.deng.framework.beans.BeansException;
import com.deng.framework.beans.PropertyValues;
import com.deng.framework.beans.factory.BeanFactory;
import com.deng.framework.beans.factory.BeanFactoryAware;
import com.deng.framework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.deng.framework.beans.factory.support.DefaultListableBeanFactory;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;

import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * AOP融入spring的最重要的函数，AOP融入spring后的三大块之一，需要在xml中进行配置后注入到spring中，有着完整的spring生命周期
 * 该类继承了InstantiationAwareBeanPostProcessor，表明这是一个BeanPostProcessor，有着和BeanPostProcessor一样的生命周期
 * 这个 DefaultAdvisorAutoProxyCreator 类的主要核心实现在于 postProcessBeforeInstantiation 方法中,在spring中使用AOP处理bean就是调用的这个函数
 */
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {

    //因为DefaultAdvisorAutoProxyCreator中需要获取所有的AspectJExpressionPointcutAdvisor来进行match，
    private DefaultListableBeanFactory beanFactory;

    //三级缓存新加的，用于存储被代理类是否已经执行过动态代理了
    private final Set<Object> earlyProxyReferences = Collections.synchronizedSet(new HashSet<Object>());

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (DefaultListableBeanFactory) beanFactory;
    }

    /**
     * 核心函数(曾经)
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        //首先判断传入的需要代理的代理类其是否为AOP相关的类，如果是，则直接返回（毕竟哪有AOP代理AOP的）
//        if (isInfrastructureClass(beanClass)) return null;
//
//        Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();
//
//        //遍历AspectJExpressionPointcutAdvisor获取切入点和自定义拦截器
//        for(AspectJExpressionPointcutAdvisor advisor : advisors){
//            ClassFilter classFilter = advisor.getPointcut().getClassFilter();
//            if(!classFilter.matches(beanClass)) continue;
//
//            //匹配成功就将其组装成一个advisedSupport，然后通过proxyFactory进行jdk动态代理或者cglib动态代理
//            AdvisedSupport advisedSupport = new AdvisedSupport();
//
//            TargetSource targetSource = null;
//            try {
//                //使用反射来创建带有构造函数的对象
//                targetSource = new TargetSource(beanClass.getDeclaredConstructor().newInstance());
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//            advisedSupport.setTargetSource(targetSource);
//            advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
//            advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
//            advisedSupport.setProxyTargetClass(false);
//
//            return new ProxyFactory(advisedSupport).getProxy();
//        }

        //上面那部分是在AOP代理的类不参加bean的生命周期时写的，现在扩充了在其生命周期之后在进行代理的功能,所以就废弃了
        return null;
    }

    /**
     * 注解部分的扩展
     */
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        return pvs;
    }

    /**
     * 实现AOP动态代理的核心部分
     */
    protected Object wrapIfNecessary(Object bean, String beanName) {
        //首先判断传入的需要代理的代理类其是否为AOP相关的类，如果是，则直接返回（毕竟哪有AOP代理AOP的）
        if (isInfrastructureClass(bean.getClass())) return bean;

        Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();

        for (AspectJExpressionPointcutAdvisor advisor : advisors) {
            ClassFilter classFilter = advisor.getPointcut().getClassFilter();
            // 过滤匹配类
            if (!classFilter.matches(bean.getClass())) continue;

            AdvisedSupport advisedSupport = new AdvisedSupport();

            TargetSource targetSource = new TargetSource(bean);
            advisedSupport.setTargetSource(targetSource);
            advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
            advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
            advisedSupport.setProxyTargetClass(true);

            // 返回代理对象
            return new ProxyFactory(advisedSupport).getProxy();
        }

        return bean;
    }

    private boolean isInfrastructureClass(Class<?> beanClass) {
        return Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass);
    }

    /**
     * 三级缓存在AOP中的扩展
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }

    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) {
        earlyProxyReferences.add(beanName);
        return wrapIfNecessary(bean, beanName);
    }

    /**
     * BeanPostProcessor部分
     *
     * 这两个是继承BeanPostProcessor自带的，DefaultAdvisorAutoProxyCreator会在spring初始化的时候就注册进ioc中
     * 所以这两个函数会在被当作BeanPostProcessor在该调用的时候调用
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    //我们将代理的实现移到了这里，通过BeanPostProcessor被调用的时候执行AOP代理
    //我们知道BeanPostProcessor会在代理类实例化之后调用，所以我们这里就完成了AOP对代理类的动态代理
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        //如果在三级缓存中已经进行了代理了，那么我们就直接返回bean，如果没进行三级缓存，那就在这一步进行代理
        if (!earlyProxyReferences.contains(beanName)) {
            return wrapIfNecessary(bean, beanName);
        }

        return bean;
    }


}
